package orm

import (
	"fmt"
	"strings"
	"sync"
	"unsafe"
)

// 这是一个有序的Map实现，内置的map是无序的，在应用中有一些不便

type ZMap[T comparable] struct {
	key   []string
	value []T
	count uint
	cap   uint
	size  uintptr
	rw    sync.RWMutex
}

func MakeZMap[T comparable](sizes ...int) *ZMap[T] {
	var _size = 0
	if len(sizes) > 0 {
		_size = sizes[0]
	}

	return &ZMap[T]{
		key:   make([]string, _size),
		value: make([]T, _size),
		count: uint(0),
		cap:   uint(_size),
		size:  uintptr(0),
	}
}

func ZMapInit[T comparable](maps map[string]T) *ZMap[T] {
	if maps == nil {
		return nil
	}
	keys := make([]string, len(maps))
	values := make([]T, len(maps))
	var sizes uintptr = 0
	var index = 0
	for k, v := range maps {
		keys[index] = k
		values[index] = v
		sizes += uintptr(len(k))
		sizes += unsafe.Sizeof(v)
		index++
	}

	return &ZMap[T]{
		key:   keys,
		value: values,
		count: uint(len(maps)),
		cap:   uint(len(maps)),
		size:  sizes,
	}
}

func (z *ZMap[T]) Set(key string, val T) {
	if key == "" {
		return
	}
	z.rw.Lock()
	defer z.rw.Unlock()

	if z.count < z.cap {
		z.key[z.count] = key
		z.value[z.count] = val
	} else {
		z.key = append(z.key, key)
		z.value = append(z.value, val)
	}

	z.count++
	z.size += uintptr(len(key))
	z.size += unsafe.Sizeof(val)
}

func (z *ZMap[T]) Sets(maps map[string]T) {
	if maps == nil {
		return
	}

	for k, v := range maps {
		z.Set(k, v)
	}
}

func (z *ZMap[T]) Get(key string) T {
	var zero T
	if key == "" || z.IsEmpty() {
		return zero
	}

	return z.value[z.Index(key)]
}

func (z *ZMap[T]) Remove(key string) bool {
	if z.IsEmpty() {
		return true
	}

	z.rw.Lock()
	defer z.rw.Unlock()

	keyIdx := z.Index(key)
	val := z.value[keyIdx]
	z.key = append(z.key[:keyIdx], z.key[keyIdx+1:]...)
	z.value = append(z.value[:keyIdx], z.value[keyIdx+1:]...)

	z.count--
	z.size -= uintptr(len(key))
	z.size -= unsafe.Sizeof(val)

	return true
}

func (z *ZMap[T]) Exist(key string) bool {
	return z.Index(key) != -1
}

func (z *ZMap[T]) Index(key string) int {
	if key == "" || z.IsEmpty() {
		return -1
	}

	for k, v := range z.key {
		if v == key {
			return k
		}
	}

	return -1
}

func (z *ZMap[T]) IsEmpty() bool {
	return z.count == 0
}

func (z *ZMap[T]) Clear() {
	z.key = make([]string, 0)
	z.value = make([]T, 0)
	z.count = 0
	z.size = 0
}

func (z *ZMap[T]) Count() uint {
	return z.count
}

func (z *ZMap[T]) Size() uintptr { return z.size }

func (z *ZMap[T]) String() string {
	if z.IsEmpty() {
		return "{}"
	}
	var i uint
	var field []string
	for i = 0; i < z.count; i++ {
		field = append(field, fmt.Sprintf(`"%s": "%v"`, z.key[i], z.value[i]))
	}

	return "{" + strings.Join(field, ", ") + "}"
}
